package com.weaving.monitor.service;

import com.weaving.monitor.dto.FlawDetailDto;
import com.weaving.monitor.dto.MachineDetailDto;
import com.weaving.monitor.dto.ProdCardTimeInfo;
import com.weaving.monitor.entity.Machine;
import com.weaving.monitor.entity.OrderDetail;
import com.weaving.monitor.entity.StaffUserOnboard;
import com.weaving.monitor.mapper.MachineMapper;
import com.weaving.monitor.mapper.OrderDetailMapper;
import com.weaving.monitor.mapper.ProdProdCardMapper;
import com.weaving.monitor.mapper.ProdProductMapper;
import com.weaving.monitor.mapper.ProdFlawMapper;
import com.weaving.monitor.mapper.StaffUserOnboardMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import com.weaving.monitor.mapper.WarpingBeamProductMapper;
import lombok.extern.slf4j.Slf4j;

/**
 * 机器详情服务类
 * 
 * 功能说明：
 * 1. 提供机器详细信息的业务逻辑处理
 * 2. 生成机器详情页面的完整数据
 * 3. 包含图表数据、故障信息、时间统计等
 * 4. 为机器详情页面提供数据支持
 * 
 * 注解说明：
 * - @Service: Spring注解，标识这是一个服务类，会被Spring容器管理
 * - @RequiredArgsConstructor: Lombok注解，自动生成包含final字段的构造函数
 * 
 * 主要功能：
 * 1. 获取机器详细信息，包括基本信息和统计数据
 * 2. 生成图表数据，支持饼图、散点图、时间图等
 * 3. 处理梳栉/盘头详情信息
 * 4. 提供默认数据，确保页面正常显示
 * 
 * 数据来源：
 * - 数据库中的机器基本信息
 * - 模拟的订单、工艺、故障等数据
 * - 计算生成的图表数据
 * 
 * @author 系统开发团队
 * @version 1.0
 * @since 2024-01-01
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class MachineDetailService {
    
    /** 经编机数据访问接口，用于查询机器基本信息 */
    private final MachineMapper machineMapper;
    
    /** 订单详情数据访问接口，用于查询订单信息 */
    private final OrderDetailMapper orderDetailMapper;
    
    /** 员工姓名服务，用于根据卡号获取员工真实姓名 */
    private final WorkerNameService workerNameService;
    
    /** 生产卡片数据访问接口，用于查询生产卡片信息 */
    private final ProdProdCardMapper prodProdCardMapper;
    
    /** 生产产品数据访问接口，用于查询产品信息 */
    private final ProdProductMapper prodProductMapper;
    
    /** 疵点数据访问接口，用于查询疵点信息 */
    private final ProdFlawMapper prodFlawMapper;
    
    /** 员工上机记录数据访问接口，用于查询员工上机时间 */
    private final StaffUserOnboardMapper staffUserOnboardMapper;

    private final FlawQueryService flawQueryService;

    private final WarpingBeamProductMapper warpingBeamProductMapper;
    
    /**
     * 获取指定机器的详细信息
     * 
     * 功能说明：
     * 1. 根据机器号获取完整的机器详细信息
     * 2. 包含基本信息、订单详情、工艺信息、图表数据等
     * 3. 如果机器不存在则返回默认数据
     * 
     * 注意：此方法已被拆分为多个子方法以提高性能
     * 建议使用以下方法替代：
     * - getMachineBasicInfo() - 基本信息
     * - getMachineChartData() - 图表数据
     * - getMachineDefectStats() - 疵点统计
     * - getMachineGuideBarDetails() - 梳栉详情
     * 
     * @param machineNumber 机器编号
     * @return 机器的详细信息，包含所有页面需要的数据
     * @deprecated 建议使用拆分后的方法以提高性能
     */
    @Deprecated
    public MachineDetailDto getMachineDetail(Integer machineNumber) {
        // 根据机器号查询机器基本信息
        Machine machine = machineMapper.selectByMachineNumber(machineNumber);
        
        // 如果机器不存在，返回默认详情
        if (machine == null) {
            return createDefaultDetail(machineNumber);
        }
        
        // 创建详情对象
        MachineDetailDto detail = new MachineDetailDto();
        
        // 设置基本信息
        detail.setMachineNumber(machineNumber);
        detail.setCurrentSpeed(machine.getSpeed() != null ? machine.getSpeed() : 0);
        
        // 从数据库查询订单详情
        String machineId = "J" + String.format("%03d", machine.getMachineNumber());
        OrderDetail orderDetail = orderDetailMapper.selectOrderDetailByMachineId(machineId);
        
        // 设置机器/订单详情
        if (orderDetail != null) {
            detail.setMaterialType(orderDetail.getMaterialType() != null ? orderDetail.getMaterialType() : "未知");
            detail.setOrderNumber(orderDetail.getOrderNumber() != null ? orderDetail.getOrderNumber() : "未知");
            detail.setOrderQuantity(orderDetail.getOrderQuantity() != null ? orderDetail.getOrderQuantity() : 0.0);
            detail.setCompletedQuantity(orderDetail.getCompletedQuantity() != null ? orderDetail.getCompletedQuantity() : 0.0);
        } else {
            detail.setMaterialType("坯布" + (machine.getL1Pattern() != null ? machine.getL1Pattern() : "ATC-440X"));
            detail.setOrderNumber("XXXXX-X");
            detail.setOrderQuantity(25000.0);
            detail.setCompletedQuantity(13527.0);
        }
        detail.setCurrentMeters(machine.getFabricLength() != null ? machine.getFabricLength().doubleValue() : 0.0);
        
        // 设置工艺/疵点详情
        // 获取processCard字段：通过SQL查询prod_prod_card表获取当前运行的生产卡片ID
        String processCard = getProcessCardByMachineId(machineId);
        detail.setProcessCard(processCard != null ? processCard : "ATC-440X");
        
        // 生产员工通过卡号转员工姓名，与卡片上保持一致
        String operatorCardNumber = machine.getOperator();
        String productionEmployee = "未知";
        if (operatorCardNumber != null && !operatorCardNumber.isEmpty()) {
            productionEmployee = workerNameService.getWorkerNameByCardNumber(operatorCardNumber);
        }
        detail.setProductionEmployee(productionEmployee);
        
        // 计算疵点数量：通过当前生产卡号processCard从prod_product表获取id列表，
        // 然后循环id去找每个id在疵点表prod_flaw中有多少停车疵点
        int parkingDefectCount = 0;
        int nonParkingDefectCount = 0;
        if (processCard != null) {
            // 获取产品ID列表
            List<String> productIds = prodProductMapper.selectProductIdsByCardId(processCard);
            if (productIds != null && !productIds.isEmpty()) {
                // 查询停车疵点数量（type=0）
                Integer parkingCount = prodFlawMapper.selectFlawCountByProductIdsAndType(productIds, 0);
                parkingDefectCount = parkingCount != null ? parkingCount : 0;
                
                // 查询非停车疵点数量（type!=0）
                Integer nonParkingCount = prodFlawMapper.selectFlawCountByProductIdsAndType(productIds, 1);
                nonParkingDefectCount = nonParkingCount != null ? nonParkingCount : 0;
            }
        }
        
        detail.setParkingDefectCount(parkingDefectCount);
        detail.setNonParkingDefectCount(nonParkingDefectCount);
        detail.setTotalDefectCount(parkingDefectCount + nonParkingDefectCount);
        
        // 设置梳栉/盘头详情
        detail.setGuideBarDetails(Arrays.asList(
            createGuideBarDetail("L1", machine.getL1Pattern() != null ? machine.getL1Pattern() : "XX-XX-XX-XX"),
            createGuideBarDetail("L2", machine.getL2Pattern() != null ? machine.getL2Pattern() : "XX-XX-XX-XX"),
            createGuideBarDetail("L3", machine.getL3Pattern() != null ? machine.getL3Pattern() : "XX-XX-XX-XX"),
            createGuideBarDetail("L4", machine.getL4Pattern() != null ? machine.getL4Pattern() : "XX-XX-XX-XX")
        ));
        
        // 生成图表数据
        detail.setChartData(createChartData(machine));
        
        return detail;
    }
    
    /**
     * 获取指定机器的基本信息
     * 
     * 功能说明：
     * 1. 获取机器基本状态和订单信息
     * 2. 包含机器号、当前速度、材料类型、订单号等
     * 3. 响应速度快，适合频繁调用
     * 
     * @param machineNumber 机器编号
     * @return 机器基本信息
     */
    public MachineDetailDto getMachineBasicInfo(Integer machineNumber) {
        // 根据机器号查询机器基本信息
        Machine machine = machineMapper.selectByMachineNumber(machineNumber);
        
        // 如果机器不存在，返回默认详情
        if (machine == null) {
            return createDefaultDetail(machineNumber);
        }
        
        // 创建详情对象
        MachineDetailDto detail = new MachineDetailDto();
        
        // 设置基本信息
        detail.setMachineNumber(machineNumber);
        detail.setCurrentSpeed(machine.getSpeed() != null ? machine.getSpeed() : 0);
        
        // 从数据库查询订单详情
        String machineId = "J" + String.format("%03d", machine.getMachineNumber());
        OrderDetail orderDetail = orderDetailMapper.selectOrderDetailByMachineId(machineId);
        
        // 设置机器/订单详情
        if (orderDetail != null) {
            detail.setMaterialType(orderDetail.getMaterialType() != null ? orderDetail.getMaterialType() : "未知");
            detail.setOrderNumber(orderDetail.getOrderNumber() != null ? orderDetail.getOrderNumber() : "未知");
            detail.setOrderQuantity(orderDetail.getOrderQuantity() != null ? orderDetail.getOrderQuantity() : 0.0);
            detail.setCompletedQuantity(orderDetail.getCompletedQuantity() != null ? orderDetail.getCompletedQuantity() : 0.0);
        } else {
            detail.setMaterialType("坯布" + (machine.getL1Pattern() != null ? machine.getL1Pattern() : "ATC-440X"));
            detail.setOrderNumber("XXXXX-X");
            detail.setOrderQuantity(25000.0);
            detail.setCompletedQuantity(13527.0);
        }
        detail.setCurrentMeters(machine.getFabricLength() != null ? machine.getFabricLength().doubleValue() : 0.0);
        
        // 设置工艺/疵点详情
        // 获取processCard字段：通过SQL查询prod_prod_card表获取当前运行的生产卡片ID
        String processCard = getProcessCardByMachineId(machineId);
        detail.setProcessCard(processCard != null ? processCard : "ATC-440X");
        
        // 生产员工通过卡号转员工姓名，与卡片上保持一致
        String operatorCardNumber = machine.getOperator();
        String productionEmployee = "未知";
        if (operatorCardNumber != null && !operatorCardNumber.isEmpty()) {
            productionEmployee = workerNameService.getWorkerNameByCardNumber(operatorCardNumber);
        }
        detail.setProductionEmployee(productionEmployee);
        
        // 设置默认的疵点数量（基本信息接口不包含详细的疵点统计）
        detail.setParkingDefectCount(0);
        detail.setNonParkingDefectCount(0);
        detail.setTotalDefectCount(0);
        
        // 设置梳栉/盘头详情
        detail.setGuideBarDetails(Arrays.asList(
            createGuideBarDetail("L1", machine.getL1Pattern() != null ? machine.getL1Pattern() : "XX-XX-XX-XX"),
            createGuideBarDetail("L2", machine.getL2Pattern() != null ? machine.getL2Pattern() : "XX-XX-XX-XX"),
            createGuideBarDetail("L3", machine.getL3Pattern() != null ? machine.getL3Pattern() : "XX-XX-XX-XX"),
            createGuideBarDetail("L4", machine.getL4Pattern() != null ? machine.getL4Pattern() : "XX-XX-XX-XX")
        ));
        
        return detail;
    }
    
    /**
     * 获取指定机器的图表数据
     * 
     * 功能说明：
     * 1. 获取订单完成进度、故障分布、时间图等图表数据
     * 2. 包含饼图、散点图、时间图等数据
     * 3. 数据量较大，建议按需调用
     * 
     * @param machineNumber 机器编号
     * @return 图表数据
     */
    public MachineDetailDto.ChartData getMachineChartData(Integer machineNumber) {
        // 根据机器号查询机器基本信息
        Machine machine = machineMapper.selectByMachineNumber(machineNumber);
        
        // 如果机器不存在，返回默认图表数据
        if (machine == null) {
            return createDefaultChartData();
        }
        
        return createChartData(machine);
    }
    
    /**
     * 获取指定机器的疵点统计
     * 
     * 功能说明：
     * 1. 获取停车疵点和非停车疵点数量统计
     * 2. 基于当前生产卡片计算
     * 3. 数据量小，响应快速
     * 
     * @param machineNumber 机器编号
     * @return 疵点统计数据
     */
    public MachineDetailDto.DefectStats getMachineDefectStats(Integer machineNumber) {
        MachineDetailDto.DefectStats defectStats = new MachineDetailDto.DefectStats();
        
        // 根据机器号查询机器基本信息
        Machine machine = machineMapper.selectByMachineNumber(machineNumber);
        if (machine == null) {
            // 如果机器不存在，返回默认数据
            defectStats.setParkingDefectCount(5);
            defectStats.setNonParkingDefectCount(7);
            defectStats.setTotalDefectCount(12);
            defectStats.setProcessCard("ATC-440X");
            return defectStats;
        }
        
        // 获取机器ID
        String machineId = "J" + String.format("%03d", machine.getMachineNumber());
        
        // 获取processCard字段：通过SQL查询prod_prod_card表获取当前运行的生产卡片ID
        String processCard = getProcessCardByMachineId(machineId);
        defectStats.setProcessCard(processCard != null ? processCard : "ATC-440X");
        
        // 计算疵点数量：通过当前生产卡号processCard从prod_product表获取id列表，
        // 然后循环id去找每个id在疵点表prod_flaw中有多少停车疵点
        int parkingDefectCount = 0;
        int nonParkingDefectCount = 0;
        if (processCard != null) {
            // 获取产品ID列表
            List<String> productIds = prodProductMapper.selectProductIdsByCardId(processCard);
            if (productIds != null && !productIds.isEmpty()) {
                // 查询停车疵点数量（type=0）
                Integer parkingCount = prodFlawMapper.selectFlawCountByProductIdsAndType(productIds, 0);
                parkingDefectCount = parkingCount != null ? parkingCount : 0;
                
                // 查询非停车疵点数量（type!=0）
                Integer nonParkingCount = prodFlawMapper.selectFlawCountByProductIdsAndType(productIds, 1);
                nonParkingDefectCount = nonParkingCount != null ? nonParkingCount : 0;
            }
        }
        
        defectStats.setParkingDefectCount(parkingDefectCount);
        defectStats.setNonParkingDefectCount(nonParkingDefectCount);
        defectStats.setTotalDefectCount(parkingDefectCount + nonParkingDefectCount);
        
        return defectStats;
    }
    
    /**
     * 获取指定机器的梳栉详情
     * 
     * 功能说明：
     * 1. 获取L1、L2、L3、L4梳栉的配置信息
     * 2. 包含梳栉编号和对应的盘头型号
     * 3. 数据量小，响应快速
     * 
     * @param machineNumber 机器编号
     * @return 梳栉详情信息
     */
    public List<MachineDetailDto.GuideBarDetail> getMachineGuideBarDetails(Integer machineNumber) {
        // 根据机器号查询机器基本信息
        Machine machine = machineMapper.selectByMachineNumber(machineNumber);
        
        // 如果机器不存在，返回默认梳栉详情
        if (machine == null) {
            return Arrays.asList(
                createGuideBarDetail("L1", "XX-XX-XX-XX"),
                createGuideBarDetail("L2", "XX-XX-XX-XX"),
                createGuideBarDetail("L3", "XX-XX-XX-XX"),
                createGuideBarDetail("L4", "XX-XX-XX-XX")
            );
        }
        
        return Arrays.asList(
            createGuideBarDetail("L1", machine.getL1Pattern() != null ? machine.getL1Pattern() : "XX-XX-XX-XX"),
            createGuideBarDetail("L2", machine.getL2Pattern() != null ? machine.getL2Pattern() : "XX-XX-XX-XX"),
            createGuideBarDetail("L3", machine.getL3Pattern() != null ? machine.getL3Pattern() : "XX-XX-XX-XX"),
            createGuideBarDetail("L4", machine.getL4Pattern() != null ? machine.getL4Pattern() : "XX-XX-XX-XX")
        );
    }
    
    /**
     * 创建默认的机器详情数据
     * 
     * 功能说明：
     * 1. 当机器不存在时，提供默认的详情数据
     * 2. 确保页面能够正常显示，不会出现数据缺失
     * 3. 使用合理的默认值，保持页面的一致性
     * 
     * @param machineNumber 机器编号
     * @return 默认的机器详情数据
     */
    private MachineDetailDto createDefaultDetail(Integer machineNumber) {
        MachineDetailDto detail = new MachineDetailDto();
        
        // 设置默认的基本信息
        detail.setMachineNumber(machineNumber);
        detail.setCurrentSpeed(120);
        detail.setMaterialType("坯布ATC-440X");
        detail.setOrderNumber("XXXXX-X");
        detail.setOrderQuantity(25000.0);
        detail.setCompletedQuantity(13527.0);
        detail.setCurrentMeters(251.3);
        detail.setProcessCard("ATC-440X");
        detail.setProductionEmployee("周世奎");
        detail.setParkingDefectCount(5);
        detail.setNonParkingDefectCount(7);
        detail.setTotalDefectCount(12);
        
        // 设置默认的梳栉/盘头详情
        detail.setGuideBarDetails(Arrays.asList(
            createGuideBarDetail("L1", "XX-XX-XX-XX"),
            createGuideBarDetail("L2", "XX-XX-XX-XX"),
            createGuideBarDetail("L3", "XX-XX-XX-XX"),
            createGuideBarDetail("L4", "XX-XX-XX-XX")
        ));
        
        // 生成默认的图表数据
        detail.setChartData(createChartData(null));
        
        return detail;
    }
    
    /**
     * 创建梳栉/盘头详情对象
     * 
     * 功能说明：
     * 1. 创建单个梳栉的详细信息
     * 2. 包含梳栉号、机上盘头号、待上机盘头号
     * 3. 为详情页面的表格提供数据
     * 4. 实现新的待分配逻辑：通过机上盘头号匹配待分配盘头列表，然后找到与machineBobbinNumber相等的下一个盘头号
     * 
     * 待分配逻辑：
     * 1. 通过机上盘头号machineBobbinNumber参数来匹配待分配盘头列表
     * 2. SQL查询：select sub_beam_code from warping_beam_product where sub_beam_code like #{machineBobbinNumber} and status='2' order by create_time asc;
     * 3. 找到与machineBobbinNumber相等的下一个盘头号
     * 
     * @param guideBarNumber 梳栉号，如L1、L2、L3、L4
     * @param machineBobbinNumber 机上盘头号
     * @return 梳栉详情对象
     */
    private MachineDetailDto.GuideBarDetail createGuideBarDetail(String guideBarNumber, String machineBobbinNumber) {
        MachineDetailDto.GuideBarDetail detail = new MachineDetailDto.GuideBarDetail();
        detail.setGuideBarNumber(guideBarNumber);
        detail.setMachineBobbinNumber(machineBobbinNumber);
        
        // 实现新的待分配逻辑
        String pendingBobbinNumber = getNextPendingBobbinNumber(machineBobbinNumber);
        detail.setPendingBobbinNumber(pendingBobbinNumber);
        
        return detail;
    }
    
    /**
     * 获取下一个待分配的盘头号
     * 
     * 功能说明：
     * 1. 通过机上盘头号匹配待分配盘头列表
     * 2. 找到与machineBobbinNumber相等的下一个盘头号
     * 3. 如果找不到匹配的盘头号，返回默认值
     * 
     * 逻辑说明：
     * 1. 将机上盘头号转换为通配符格式（如：5-25-8-29-A-1 -> 5-25-8-29-%-1）
     * 2. 查询待分配盘头列表：sub_beam_code like #{machineBobbinNumber} and status='2'
     * 3. 按create_time升序排列
     * 4. 找到与machineBobbinNumber相等的下一个盘头号
     * 
     * @param machineBobbinNumber 机上盘头号
     * @return 下一个待分配的盘头号，如果找不到则返回"待分配"
     */
    private String getNextPendingBobbinNumber(String machineBobbinNumber) {
        try {
            // 如果机上盘头号为空或无效，返回默认值
            if (machineBobbinNumber == null || machineBobbinNumber.trim().isEmpty() || 
                "XX-XX-XX-XX".equals(machineBobbinNumber)) {
                return "待分配";
            }
            
            // 将机上盘头号转换为通配符格式
            // 例如：5-25-8-29-A-1 -> 5-25-8-29-%-1
            String searchPattern = convertToSearchPattern(machineBobbinNumber);
            
            // 查询待分配盘头列表
            List<String> pendingBobbinNumbers = warpingBeamProductMapper.selectPendingBobbinNumbersByMachineBobbinNumber(searchPattern);
            
            if (pendingBobbinNumbers == null || pendingBobbinNumbers.isEmpty()) {
                return "待分配";
            }
            
            // 找到与machineBobbinNumber相等的下一个盘头号
            // 由于SQL查询已经按create_time升序排列，我们取第一个匹配的盘头号
            for (String bobbinNumber : pendingBobbinNumbers) {
                if (bobbinNumber != null && bobbinNumber.equals(machineBobbinNumber)) {
                    // 找到相等的盘头号，返回下一个（如果存在）
                    int currentIndex = pendingBobbinNumbers.indexOf(bobbinNumber);
                    if (currentIndex + 1 < pendingBobbinNumbers.size()) {
                        return pendingBobbinNumbers.get(currentIndex + 1);
                    } else {
                        // 如果没有下一个，返回当前盘头号
                        return bobbinNumber;
                    }
                }
            }
            
            // 如果没有找到相等的盘头号，返回第一个待分配的盘头号
            return pendingBobbinNumbers.get(0);
            
        } catch (Exception e) {
            // 如果查询过程中出现异常，返回默认值
            log.error("查询待分配盘头号时发生异常，机上盘头号: {}", machineBobbinNumber, e);
            return "待分配";
        }
    }
    
    /**
     * 将机上盘头号转换为搜索模式
     * 
     * 功能说明：
     * 1. 将机上盘头号转换为通配符格式，用于LIKE查询
     * 2. 保持长度一致，只替换最后一个非连字符的部分为通配符
     * 
     * 转换规则：
     * - 输入：5-25-8-29-A-1
     * - 输出：5-25-8-29-%-1
     * 
     * @param machineBobbinNumber 机上盘头号
     * @return 转换后的搜索模式
     */
    private String convertToSearchPattern(String machineBobbinNumber) {
        if (machineBobbinNumber == null || machineBobbinNumber.trim().isEmpty()) {
            return machineBobbinNumber;
        }
        
        // 按连字符分割盘头号
        String[] parts = machineBobbinNumber.split("-");
        
        if (parts.length < 2) {
            // 如果分割后少于2个部分，直接返回原值
            return machineBobbinNumber;
        }
        
        // 找到最后一个非连字符的部分（倒数第二个部分）
        int lastNonDashIndex = parts.length - 2;
        
        // 构建搜索模式：将倒数第二个部分替换为通配符
        StringBuilder pattern = new StringBuilder();
        for (int i = 0; i < parts.length; i++) {
            if (i > 0) {
                pattern.append("-");
            }
            if (i == lastNonDashIndex) {
                pattern.append("%");
            } else {
                pattern.append(parts[i]);
            }
        }
        
        return pattern.toString();
    }
    
    /**
     * 创建图表数据
     * 
     * 功能说明：
     * 1. 生成机器详情页面需要的所有图表数据
     * 2. 包含订单完成进度饼图、故障分布散点图、时间图
     * 3. 根据实际机器数据计算完成进度
     * 
     * 图表类型：
     * - 订单完成进度饼图：显示已完成和订单数量
     * - 故障分布散点图：显示各种故障的位置分布
     * - 时间图：显示员工工作时间统计
     * 
     * @param machine 机器对象，如果为null则使用默认数据
     * @return 包含所有图表数据的对象
     */
    private MachineDetailDto.ChartData createChartData(Machine machine) {
        MachineDetailDto.ChartData chartData = new MachineDetailDto.ChartData();
        
        // 从数据库查询订单详情用于饼图数据
        String machineId = null;
        OrderDetail orderDetail = null;
        
        if (machine != null) {
            machineId = "J" + String.format("%03d", machine.getMachineNumber());
            orderDetail = orderDetailMapper.selectOrderDetailByMachineId(machineId);
        }
        
        // 生成订单完成进度饼图数据
        double completedQuantity = 0;
        double orderQuantity = 0;
        
        // 如果有实际订单数据，使用数据库中的值
        if (orderDetail != null) {
            completedQuantity = orderDetail.getCompletedQuantity() != null ? orderDetail.getCompletedQuantity() : 0.0;
            orderQuantity = orderDetail.getOrderQuantity() != null ? orderDetail.getOrderQuantity() : 0.0;
        }
        
        // 计算剩余数量
        double remainingQuantity = Math.max(0, orderQuantity - completedQuantity);
        
        chartData.setCompletionData(Arrays.asList(
            createCompletionData("已完成数量(米)", completedQuantity, "#2196F3"),
            createCompletionData("剩余数量(米)", remainingQuantity, "#FF9800")
        ));

        // 从数据库获取真实的故障分布数据
        List<MachineDetailDto.FaultData> faultDataList = new ArrayList<>();
        if (machineId != null) {
            List<FlawDetailDto> flaws = flawQueryService.queryCurrentFlawDetailsByMachineId(machineId);
            if (flaws != null && !flaws.isEmpty()) {
                for (FlawDetailDto flaw : flaws) {
                    // 根据疵点类型获取对应的颜色
                    String color = getFlawTypeColor(flaw.getType());
                    // 根据疵点类型获取对应的名称
                    String typeName = getFlawTypeName(flaw.getType());
                    
                    // 创建故障数据点
                    MachineDetailDto.FaultData faultData = createFaultData(
                        typeName, 
                        Double.parseDouble(flaw.getPosition()), 
                        flaw.getType(), 
                        color
                    );
                    faultDataList.add(faultData);
                }
            }
        }
        
        // 如果没有真实数据，使用默认数据
        if (faultDataList.isEmpty()) {
            faultDataList = Arrays.asList(
                // 无故障点
                createFaultData("无故障", 50.0, 0, "#2196F3"),
                createFaultData("无故障", 100.0, 0, "#2196F3"),
                createFaultData("无故障", 150.0, 0, "#2196F3"),
                createFaultData("无故障", 200.0, 0, "#2196F3"),
                createFaultData("无故障", 250.0, 0, "#2196F3")

            );
        }
        
        chartData.setFaultData(faultDataList);
        
        // 生成时间图数据
        if (machineId != null) {
            chartData.setTimeData(generateTimeDataFromDatabase(machineId));
        } else {
            // 使用默认的时间图数据
            chartData.setTimeData(Arrays.asList(
                createTimeData("无", 24, "#FF00FF", "00:00", "24:00")
            ));
        }
        
        return chartData;
    }

    /**
     * 根据疵点类型获取对应的名称
     * 
     * 功能说明：
     * 1. 根据疵点类型编号返回对应的中文名称
     * 2. 与前端app.js中的FLAW_TYPE_MAP保持一致
     * 
     * @param type 疵点类型编号
     * @return 疵点类型名称
     */
    private String getFlawTypeName(Integer type) {
        if (type == null) {
            return "未知类型";
        }
        
        switch (type) {
            case 0: return "停车位";
            case 1: return "横条";
            case 2: return "断头";
            case 3: return "长断头";
            case 4: return "油污";
            case 5: return "漏针";
            case 6: return "其他";
            case 8: return "抛丝";
            case 9: return "吊丝";
            case 10: return "勾丝";
            case 11: return "油污丝";
            case 12: return "导电丝异常";
            case 13: return "毛针";
            case 14: return "其他";
            case 16: return "破洞";
            case 17: return "隐横路";
            case 18: return "坏边右";
            case 21: return "拼缝";
            case 22: return "吊丝";
            case 23: return "色丝（僵丝）";
            case 24: return "盘头印";
            case 25: return "轮胎印";
            case 26: return "叉针";
            case 27: return "钓伤";
            case 28: return "漏针";
            case 29: return "下边";
            case 33: return "毛丝";
            case 34: return "粘丝";
            case 35: return "理边丝";
            case 37: return "盘头毛刺";
            case 38: return "勾丝";
            case 48: return "理直条";
            default: return "类型" + type;
        }
    }
    
    /**
     * 根据疵点类型获取对应的颜色
     * 
     * 功能说明：
     * 1. 根据疵点类型编号返回对应的颜色值
     * 2. 不同类型的疵点使用不同的颜色以便区分
     * 
     * @param type 疵点类型编号
     * @return 颜色值（十六进制）
     */
    private String getFlawTypeColor(Integer type) {
        if (type == null) {
            return "#999999"; // 默认灰色
        }
        
        switch (type) {
            case 0: return "#000000"; // 停车位 - 黑色
            case 1: return "#FF5722"; // 横条 - 深橙色
            case 2: return "#F44336"; // 断头 - 红色
            case 3: return "#E91E63"; // 长断头 - 粉红色
            case 4: return "#9C27B0"; // 油污 - 紫色
            case 5: return "#673AB7"; // 漏针 - 深紫色
            case 6: return "#3F51B5"; // 其他 - 靛蓝色
            case 8: return "#2196F3"; // 抛丝 - 蓝色
            case 9: return "#03A9F4"; // 吊丝 - 浅蓝色
            case 10: return "#00BCD4"; // 勾丝 - 青色
            case 11: return "#009688"; // 油污丝 - 青绿色
            case 12: return "#4CAF50"; // 导电丝异常 - 绿色
            case 13: return "#8BC34A"; // 毛针 - 浅绿色
            case 14: return "#CDDC39"; // 其他 - 酸橙色
            case 16: return "#FFEB3B"; // 破洞 - 黄色
            case 17: return "#FFC107"; // 隐横路 - 琥珀色
            case 18: return "#FF9800"; // 坏边右 - 橙色
            case 21: return "#FF5722"; // 拼缝 - 深橙色
            case 22: return "#795548"; // 吊丝 - 棕色
            case 23: return "#9E9E9E"; // 色丝（僵丝） - 灰色
            case 24: return "#607D8B"; // 盘头印 - 蓝灰色
            case 25: return "#000000"; // 轮胎印 - 黑色
            case 26: return "#F44336"; // 叉针 - 红色
            case 27: return "#E91E63"; // 钓伤 - 粉红色
            case 28: return "#9C27B0"; // 漏针 - 紫色
            case 29: return "#673AB7"; // 下边 - 深紫色
            case 33: return "#3F51B5"; // 毛丝 - 靛蓝色
            case 34: return "#2196F3"; // 粘丝 - 蓝色
            case 35: return "#03A9F4"; // 理边丝 - 浅蓝色
            case 37: return "#00BCD4"; // 盘头毛刺 - 青色
            case 38: return "#009688"; // 勾丝 - 青绿色
            case 48: return "#4CAF50"; // 理直条 - 绿色
            default: return "#999999"; // 默认灰色
        }
    }

    /**
     * 创建默认的图表数据
     * 
     * 功能说明：
     * 1. 当机器不存在时，提供默认的图表数据
     * 2. 确保页面能够正常显示，不会出现数据缺失
     * 3. 使用合理的默认值，保持页面的一致性
     * 
     * @return 默认的图表数据
     */
    private MachineDetailDto.ChartData createDefaultChartData() {
        MachineDetailDto.ChartData chartData = new MachineDetailDto.ChartData();
        
        // 生成订单完成进度饼图数据
        double completedQuantity = 13527.0;
        double orderQuantity = 25000.0;
        
        // 计算剩余数量
        double remainingQuantity = Math.max(0, orderQuantity - completedQuantity);
        
        chartData.setCompletionData(Arrays.asList(
            createCompletionData("已完成数量(米)", completedQuantity, "#2196F3"),
            createCompletionData("剩余数量(米)", remainingQuantity, "#FF9800")
        ));
        
        // 生成默认的故障分布散点图数据
        chartData.setFaultData(Arrays.asList(
            // 无故障点
            createFaultData("无故障", 50.0, 0, "#2196F3"),
            createFaultData("无故障", 100.0, 0, "#2196F3"),
            createFaultData("无故障", 150.0, 0, "#2196F3"),
            createFaultData("无故障", 200.0, 0, "#2196F3"),
            createFaultData("无故障", 250.0, 0, "#2196F3"),
            // 停车位
            createFaultData("停车位", 30.0, 0, "#000000"),
            createFaultData("停车位", 80.0, 0, "#000000"),
            createFaultData("停车位", 130.0, 0, "#000000"),
            createFaultData("停车位", 180.0, 0, "#000000"),
            createFaultData("停车位", 230.0, 0, "#000000"),
            // 横条
            createFaultData("横条", 45.0, 1, "#FF5722"),
            createFaultData("横条", 95.0, 1, "#FF5722"),
            createFaultData("横条", 145.0, 1, "#FF5722"),
            // 断头
            createFaultData("断头", 60.0, 2, "#F44336"),
            createFaultData("断头", 110.0, 2, "#F44336"),
            createFaultData("断头", 160.0, 2, "#F44336"),
            // 油污
            createFaultData("油污", 75.0, 4, "#9C27B0"),
            createFaultData("油污", 125.0, 4, "#9C27B0"),
            createFaultData("油污", 175.0, 4, "#9C27B0")
        ));
        
        // 生成时间图数据
        chartData.setTimeData(Arrays.asList(
            createTimeData("徐丽娜", 10, "#FF00FF", "06:00", "16:00"),
            createTimeData("周仕奎", 14, "#FFA500", "16:00", "06:00")
        ));
        
        return chartData;
    }
    
    /**
     * 创建订单完成进度数据
     * 
     * @param label 标签名称
     * @param value 数值
     * @param color 颜色代码
     * @return 完成进度数据对象
     */
    private MachineDetailDto.CompletionData createCompletionData(String label, Double value, String color) {
        MachineDetailDto.CompletionData data = new MachineDetailDto.CompletionData();
        data.setLabel(label);
        data.setValue(value);
        data.setColor(color);
        return data;
    }
    
    /**
     * 创建故障数据
     * 
     * @param type 故障类型
     * @param x X坐标（位置）
     * @param y Y坐标（故障类型）
     * @param color 颜色代码
     * @return 故障数据对象
     */
    private MachineDetailDto.FaultData createFaultData(String type, Double x, Integer y, String color) {
        MachineDetailDto.FaultData data = new MachineDetailDto.FaultData();
        data.setType(type);
        data.setX(x);
        data.setY(y);
        data.setColor(color);
        return data;
    }
    
    /**
     * 创建时间数据
     * 
     * @param employee 员工姓名
     * @param hours 工作时间（小时）
     * @param color 颜色代码
     * @param startTime 开始时间（HH:mm格式）
     * @param endTime 结束时间（HH:mm格式）
     * @return 时间数据对象
     */
    private MachineDetailDto.TimeData createTimeData(String employee, Integer hours, String color, String startTime, String endTime) {
        MachineDetailDto.TimeData data = new MachineDetailDto.TimeData();
        data.setEmployee(employee);
        data.setHours(hours);
        data.setColor(color);
        data.setStartTime(startTime);
        data.setEndTime(endTime);
        return data;
    }
    
    /**
     * 根据机器ID获取当前运行的生产卡片ID
     * 
     * 功能说明：
     * 1. 通过SQL查询prod_prod_card表获取当前运行的生产卡片ID
     * 2. 查询条件：status='1' and machine_id=指定的机器ID
     * 3. 返回生产卡片ID，用于工艺/疵点详情显示
     * 
     * SQL语句：
     * SELECT id FROM prod_prod_card WHERE status='1' AND machine_id='J001'
     * 
     * @param machineId 机器ID，格式如J001
     * @return 生产卡片ID，如果查询不到则返回null
     */
    private String getProcessCardByMachineId(String machineId) {
        try {
            // 通过Mapper查询数据库获取当前运行的生产卡片ID
            return prodProdCardMapper.selectProcessCardIdByMachineId(machineId);
        } catch (Exception e) {
            // 如果查询失败，返回null
            return null;
        }
    }
    
    /**
     * 从数据库生成时间图数据
     * 
     * 功能说明：
     * 1. 根据当前机台运行的生产卡起始时间作为时间轴的起始时间
     * 2. 通过机台号查询staff_user_onboard表对应的上机时间和下机时间
     * 3. 通过staff_user_onboard表中的user_id关联sys_user表的id查询对应时间段内的realname
     * 4. 正在生产的生产卡endDate为null，则用当前时间作为endDate
     * 
     * 处理流程：
     * 1. 查询当前机台的生产卡片起始时间和结束时间
     * 2. 如果正在生产（endDate为null），使用当前时间作为结束时间
     * 3. 根据时间范围查询员工上机记录
     * 4. 通过用户ID查询员工真实姓名
     * 5. 计算工作时间并生成TimeData
     * 
     * @param machineId 机台ID，如J001
     * @return 时间图数据列表
     */
    private List<MachineDetailDto.TimeData> generateTimeDataFromDatabase(String machineId) {
        try {
            // 1. 查询当前机台的生产卡片起始时间和结束时间
            ProdCardTimeInfo timeInfo = prodProdCardMapper.selectProcessCardTimeByMachineId(machineId);
            if (timeInfo == null || timeInfo.getStartDate() == null) {
                // 如果没有生产卡片信息，返回默认数据
                return Arrays.asList(
                    createTimeData("徐丽娜", 10, "#FF00FF", "06:00", "16:00"),
                    createTimeData("周仕奎", 14, "#FFA500", "16:00", "06:00")
                );
            }
            
            // 2. 确定时间范围
            Date startDate = timeInfo.getStartDate();
            Date endDate = timeInfo.getEndDate();
            if (endDate == null) {
                // 如果正在生产（endDate为null），使用当前时间作为结束时间
                endDate = new Date();
            }
            
            // 3. 根据时间范围查询员工上机记录
            List<StaffUserOnboard> onboardRecords = staffUserOnboardMapper.selectByMachineIdAndTimeRange(
                machineId, startDate, endDate);
            
            if (onboardRecords == null || onboardRecords.isEmpty()) {
                // 如果没有上机记录，返回默认数据
                return Arrays.asList(
                    createTimeData("徐丽娜", 10, "#FF00FF", "06:00", "16:00"),
                    createTimeData("周仕奎", 14, "#FFA500", "16:00", "06:00")
                );
            }
            
            // 4. 生成TimeData列表
            List<MachineDetailDto.TimeData> timeDataList = new ArrayList<>();
            String[] colors = {"#FF00FF", "#FFA500", "#2196F3", "#4CAF50", "#9C27B0", "#FF5722"};
            int colorIndex = 0;
            
            for (StaffUserOnboard record : onboardRecords) {
                // 通过用户ID查询员工真实姓名
                String employeeName = workerNameService.getWorkerNameByUserId(record.getUserId());
                if (employeeName == null || employeeName.equals("--")) {
                    employeeName = "未知员工";
                }
                
                // 计算工作时间（小时）
                Date recordEndTime = record.getGetOffTime();
                if (recordEndTime == null) {
                    // 如果下机时间为null，使用当前时间
                    recordEndTime = new Date();
                }
                
                long workHours = (recordEndTime.getTime() - record.getGetOnTime().getTime()) / (1000 * 60 * 60);
                
                // 格式化时间
                String startTime = formatTime(record.getGetOnTime());
                String endTime = formatTime(recordEndTime);
                
                // 创建TimeData
                MachineDetailDto.TimeData timeData = createTimeData(
                    employeeName, 
                    (int) workHours, 
                    colors[colorIndex % colors.length], 
                    startTime, 
                    endTime
                );
                
                timeDataList.add(timeData);
                colorIndex++;
            }
            
            return timeDataList;
            
        } catch (Exception e) {
            // 如果查询失败，返回默认数据
            System.err.println("生成时间图数据失败，机台ID: " + machineId + ", 错误: " + e.getMessage());
            return Arrays.asList(
                createTimeData("徐丽娜", 10, "#FF00FF", "06:00", "16:00"),
                createTimeData("周仕奎", 14, "#FFA500", "16:00", "06:00")
            );
        }
    }
    
    /**
     * 格式化时间为HH:mm格式
     * 
     * @param date 时间对象
     * @return 格式化后的时间字符串
     */
    private String formatTime(Date date) {
        if (date == null) {
            return "--";
        }
        
        java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("HH:mm");
        return sdf.format(date);
    }
} 